package com.clp.protocol.iec104.server;

import com.clp.protocol.iec104.apdu.asdu.IAsdu;
import com.clp.protocol.iec104.common.IncorrectRtuAddrException;
import com.clp.protocol.iec104.server.pipeline.InternalIAsduSender;
import com.clp.protocol.iec104.server.pipeline.state.control.ControlInfo;
import com.clp.protocol.iec104.server.pipeline.PipelineManager;
import com.clp.protocol.core.utils.AssertUtil;
import io.netty.channel.EventLoop;
import io.netty.channel.socket.SocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.Objects;
import java.util.concurrent.Executor;

@Slf4j
public class InSlaveChannel implements SlaveChannel {
    private final InSlave inSlave;

    private final SocketChannel channel;
    private final String remoteHost;
    private final int remotePort;

    private final Executor executor; // 仅用实际的eventloop
    private final InSlaveChannelApduRecver apduRecver;

    private final PipelineManager pipelineManager;

    public InSlaveChannel(InSlave inSlave, SocketChannel channel, SlaveControlConfig controlConfig, SlaveDataConfig dataConfig) {
        this.inSlave = inSlave;
        this.channel = channel;
        InetSocketAddress address = channel.remoteAddress();
        this.remoteHost = address.getHostString();
        this.remotePort = address.getPort();
        this.executor = command -> {
            EventLoop eventLoop = channel().eventLoop();
            if (eventLoop.inEventLoop()) {
                command.run();
            } else {
                eventLoop.execute(command);
            }
        };
        this.apduRecver = new InSlaveChannelApduRecver(this);
        this.pipelineManager = new PipelineManager(this, controlConfig, dataConfig);
    }

    public SocketChannel channel() {
        AssertUtil.notNull(channel, "channel");
        return channel;
    }

    public void init() {
        // TODO 初始化子站
    }

    @Override
    public Executor executor() {
        return executor;
    }

    @Override
    public InSlave slave() {
        return inSlave;
    }

    @Override
    public String remoteHost() {
        return remoteHost;
    }

    @Override
    public int remotePort() {
        return remotePort;
    }

    @Override
    public ControlInfo controlInfo() {
        return pipelineManager;
    }

    @Override
    public InternalIAsduSender getIAsduSender() {
        return pipelineManager.getIAsduSender();
    }

    public TcTokenPool getTcTokenPool() {
        return inSlave.getTcTokenPool();
    }

    public TaTokenPool getTaTokenPool() {
        return inSlave.getTaTokenPool();
    }

    public IAsdu handleRecving(IAsdu iAsdu) throws IncorrectRtuAddrException {
        // 检查公共地址
        checkRecvApduRtuAddr(iAsdu);
//        // 3、更新主站状态
//        iAsdu = stateInfo().updateStateByRecving(iAsdu);
//        // 4、执行回调
//        getApduRecver().handleRecvCallbacks(iAsdu);
        return iAsdu;
    }

    private void checkRecvApduRtuAddr(IAsdu iAsdu) throws IncorrectRtuAddrException {
        int recvedRtuAddr = iAsdu.getRtuAddr();
        int rtuAddr = inSlave.rtuAddr();
        if (recvedRtuAddr != rtuAddr) {
            throw new IncorrectRtuAddrException(rtuAddr, recvedRtuAddr);
        }
    }

    public IAsdu handleSending(IAsdu iAsdu) {
        // 更新主站状态
//        iAsdu = stateInfo().updateStateBySending(iAsdu);
        return iAsdu;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        InSlaveChannel that = (InSlaveChannel) o;
        return Objects.equals(remoteHost, that.remoteHost);
    }

    @Override
    public int hashCode() {
        return Objects.hash(remoteHost);
    }

    @Override
    public String toString() {
        return "<InSlaveChannel:remoteHost=>" + remoteHost + ",remotePort=" + remotePort + ">";
    }
}
